package com.andy.sqlSession;

import com.andy.pojo.Configuration;
import com.andy.pojo.MappedStatement;
import com.andy.utils.ParameterMapping;
import com.andy.utils.UnderCamelUtil;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleExecutor implements Executor {
    private Connection connection=null;

    /**
     * 创建preparedStatement，并赋值占位符
     * @param configuration
     * @param mappedStatement
     * @param param
     * @return
     * @throws SQLException
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    private PreparedStatement createPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object[] param) throws SQLException, NoSuchFieldException, IllegalAccessException {
        //获取带#{}填充字符的sql
        String sql = mappedStatement.getSql();
        //封装成boundSql(就是把#{}转义为?,并记录一个预编译需要填入参数的列表)
        BoundSql boundSql = new BoundSql(sql);
        //转义后的sql
        String finalSql = boundSql.getSqlText();
        //入参类型
        Class<?> paramType = mappedStatement.getParamType();
        //入参填充的字段
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

        //JDBC:获取连接
        connection = configuration.getDataSource().getConnection();
        //JDBC:获取preparedStatement
        PreparedStatement preparedStatement = connection.prepareStatement(finalSql);
        //JDBC:占位符赋值
        for (int i = 0; i < parameterMappings.size(); i++) {
            ParameterMapping parameterMapping = parameterMappings.get(i);
            String fieldName = parameterMapping.getContent();
            //获取字段并允许暴力访问
            Field declaredField = paramType.getDeclaredField(fieldName);
            declaredField.setAccessible(true);
            //参数的值
            Object o = declaredField.get(param[0]);
            //占位符赋值
            preparedStatement.setObject(i+1,o);
        }

        return preparedStatement;
    }

    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object[] param) throws Exception {
        //准备preparedStatement
        PreparedStatement preparedStatement = createPreparedStatement(configuration, mappedStatement, param);

        //JDBC:执行查询
        ResultSet resultSet = preparedStatement.executeQuery();

        //出参类型
        Class<?> resulType = mappedStatement.getResulType();
        //出参对象列表
        List<E> results = new ArrayList<E>();
        //循环结果集，创建出参对象放入出参列表
        while(resultSet.next()){
            ResultSetMetaData metaData = resultSet.getMetaData();
            E o = (E)resulType.newInstance();
            //放入属性
            int columnCount = metaData.getColumnCount();
            for (int i=1;i<=columnCount;i++){
                //属性名称
                String columnName = metaData.getColumnName(i);
                //属性值
                Object value = resultSet.getObject(columnName);
                //下划线转驼峰
                String fieldName = UnderCamelUtil.under2camel(columnName);
                //属性读写方法
                PropertyDescriptor propertyDescriptor = new
                        PropertyDescriptor(fieldName, resulType);
                //写方法
                Method writeMethod = propertyDescriptor.getWriteMethod();
                //反射写入值
                writeMethod.invoke(o,value);
            }

            //放入出参列表
            results.add(o);
        }

        return results;
    }

    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object[] param) throws Exception {
        //准备preparedStatement
        PreparedStatement preparedStatement = createPreparedStatement(configuration, mappedStatement, param);

        //JDBC:执行插入
        return preparedStatement.executeUpdate();
    }


    @Override
    public void close() throws SQLException {
        connection.close();
    }


}
